﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using System.Data;
using Kooboo.Collections;
using System.ComponentModel.Composition;

namespace Kooboo.Commerce.Repositories
{

    [Export(typeof(IProductRepository))]
    public partial class EntityRepositories : IProductRepository
    {
        #region Products

        public IQueryable<IProduct> Products
        {
            get
            {
                return this.DataReaderContext.Products;
            }
        }

        public void Post(IProduct product)
        {
            var callbacks = new List<Action>();

            Contract.Requires(product != null);

            if (product == null)
            {
                throw new NoNullAllowedException("Post(IProduct product)");
            }

            var item = new Product();

            ((IProduct)item).Brand = product.Brand;

            item.Description = product.Description;
            item.Name = product.Name;
            ((IProduct)item).ProductType = product.ProductType;
            item.PackageSize = product.PackageSize;
            item.Summary = product.Summary;
            item.Weight = product.Weight;

            if (product.Tax == null)
            {
                item.TaxId = null;
            }
            else
            {
                item.TaxId = product.Tax.Id;
            }

            this.DataWriterContext.Products.InsertOnSubmit(item);


            foreach (var i in product.ProductCustomFields)
            {
                var field = new ProductCustomField
                {
                    CustomFieldId = i.CustomField.Id,
                    DateTimeValue = i.DateTimeValue,
                    NumberValue = i.NumberValue,
                    Product = item,
                    Value = i.Value
                };

                this.DataWriterContext.ProductCustomFields.InsertOnSubmit(field);
            }


            foreach (var i in product.SaleItems)
            {
                var saleItem = new SaleItem
                {
                    DeliveryDays = i.DeliveryDays,
                    Product = item,
                    PurchasePrice = i.PurchasePrice,
                    RetailPrice = i.RetailPrice,
                    SKU = i.SKU,
                    Stock = i.Stock
                };

                this.DataWriterContext.SaleItems.InsertOnSubmit(saleItem);

                foreach (var n in i.ProductVariations)
                {
                    var variation = new ProductVariation
                    {
                        DateTimeValue = n.DateTimeValue,
                        NumberValue = n.NumberValue,
                        SaleItem = saleItem,
                        Value = n.Value,
                        VariationId = n.Variation.Id
                    };

                    this.DataWriterContext.ProductVariations.InsertOnSubmit(variation);
                    this.DataWriterContext.SubmitChanges();
                }
            }

            foreach (var i in product.ProductImages)
            {
                var img = new ProductImage()
                {
                    Name = i.Name,
                    CoverImage = i.CoverImage,
                    Product = item
                };

                this.DataWriterContext.ProductImages.InsertOnSubmit(img);
            }

            foreach (var i in product.Categories)
            {
                var categoryProduct = new CategoryProduct()
                {
                    CategoryId = i.Id,
                    ProductId = product.Id
                };
                this.DataWriterContext.CategoryProducts.InsertOnSubmit(categoryProduct);
            }

            this.DataWriterContext.SubmitChanges();

            
            product.Id = item.Id;

        }

        public void Put(IProduct product)
        {
            Contract.Requires(product != null);

            var item = this.DataWriterContext.Products
                .Where(i => i.Id == product.Id)
                .FirstOrDefault();

            if (item == null)
            {
                throw new KeyNotFoundException("Product:" + product.Id.ToString());
            }
            if (product.Brand != null)
                item.BrandId = product.Brand.Id;
            else
                item.BrandId = null;
            item.Description = product.Description;
            item.Name = product.Name;
            ((IProduct)item).ProductType = product.ProductType;
            item.PackageSize = product.PackageSize;
            item.Summary = product.Summary;
            item.Weight = product.Weight;


            if (product.Tax == null)
            {
                item.TaxId = null;
            }
            else
            {
                item.TaxId = product.Tax.Id;
            }

            #region CustomFields
            var fields = this.DataWriterContext.ProductCustomFields.Where(i => i.ProductId == item.Id).ToList();

            var result_fields = fields.Compare(product.ProductCustomFields, (m, n) => m.Id == n.Id, (m, n) =>
            {
                m.CustomField = n.CustomField;
                m.DateTimeValue = n.DateTimeValue;
                m.NumberValue = n.NumberValue;
                m.Value = n.Value;
            });


            foreach (var i in result_fields.Added)
            {
                var field = new ProductCustomField
                {
                    CustomFieldId = i.CustomField.Id,
                    DateTimeValue = i.DateTimeValue,
                    NumberValue = i.NumberValue,
                    Product = item,
                    Value = i.Value
                };

                this.DataWriterContext.ProductCustomFields.InsertOnSubmit(field);
            }

            foreach (var i in result_fields.Deleted)
            {
                this.DataWriterContext.ProductCustomFields.DeleteOnSubmit(i as ProductCustomField);
            }
            #endregion

            #region SaleItems
            var saleItems = this.DataWriterContext.SaleItems
                .Where(i => i.ProductId == item.Id)
                .ToList();

            var saleItems_result = saleItems.Compare(product.SaleItems, (i1, i2) => i1.Id == i2.Id, (i1, i2) =>
                {
                    i1.DeliveryDays = i2.DeliveryDays;
                    i1.PurchasePrice = i2.PurchasePrice;
                    i1.RetailPrice = i2.RetailPrice;
                    i1.SKU = i2.SKU;
                    i1.Stock = i2.Stock;

                    var variation_result = i1.ProductVariations.Compare(i2.ProductVariations, (n1, n2) => n1.Id == n2.Id, (n1, n2) =>
                         {
                             n1.DateTimeValue = n2.DateTimeValue;
                             n1.NumberValue = n2.NumberValue;
                             n1.Value = n2.Value;
                             n1.Variation = n2.Variation;
                         });
                    foreach (var m in variation_result.Added)
                    {
                        var productVariation = new ProductVariation
                        {
                            DateTimeValue = m.DateTimeValue,
                            NumberValue = m.NumberValue,
                            Value = m.Value,
                            VariationId = m.Variation.Id,
                            SaleItemId = item.Id
                        };

                        this.DataWriterContext.ProductVariations.InsertOnSubmit(productVariation);
                    }

                    foreach (var m in variation_result.Deleted)
                    {
                        this.DataWriterContext.ProductVariations.DeleteOnSubmit((ProductVariation)m);
                    }

                });


            foreach (var i in saleItems_result.Added)
            {
                var saleItem = new SaleItem
                {
                    DeliveryDays = i.DeliveryDays,
                    Product = item,
                    PurchasePrice = i.PurchasePrice,
                    RetailPrice = i.RetailPrice,
                    SKU = i.SKU,
                    Stock = i.Stock
                };

                this.DataWriterContext.SaleItems.InsertOnSubmit(saleItem);

                foreach (var n in i.ProductVariations)
                {
                    var variation = new ProductVariation
                    {
                        DateTimeValue = n.DateTimeValue,
                        NumberValue = n.NumberValue,
                        SaleItem = saleItem,
                        Value = n.Value,
                        VariationId = n.Variation.Id
                    };

                    this.DataWriterContext.ProductVariations.InsertOnSubmit(variation);
                }
            }


            foreach (var i in saleItems_result.Deleted)
            {
                var saleitem = (SaleItem)i;

                this.DataWriterContext.ProductVariations.DeleteAllOnSubmit(saleitem.ProductVariations);
                this.DataWriterContext.SaleItems.DeleteOnSubmit((SaleItem)i);
            }

            #endregion

            #region ProductImage
            var images = ((IProduct)item).ProductImages.Compare(product.ProductImages, (i1, i2) => i1.Id == i2.Id,
                   (i1, i2) =>
                   {
                       i1.Name = i2.Name;
                       i1.CoverImage = i2.CoverImage;
                   });


            foreach (var i in images.Deleted)
            {
                this.DataWriterContext.ProductImages.DeleteOnSubmit((ProductImage)i);
            }


            foreach (var i in images.Added)
            {
                var img = new ProductImage()
                {
                    Name = i.Name,
                    CoverImage = i.CoverImage,
                    Product = item
                };

                this.DataWriterContext.ProductImages.InsertOnSubmit(img);
            }
            #endregion

            #region Produt categories
            
            var links= this.DataWriterContext.CategoryProducts
                .Where(i=>i.ProductId == product.Id)
                .Select(i=>i.CategoryId);

            var catgoryIds = links.Compare(product.Categories.Select(i=> i.Id),(c1,c2)=>c1 == c2);

            //remove category
            foreach (var i in catgoryIds.Deleted)
            {
                var link = this.DataWriterContext.CategoryProducts.Where(n => n.CategoryId == i && n.ProductId == product.Id);
                this.DataWriterContext.CategoryProducts.DeleteAllOnSubmit(link);
            }

            //add category
            foreach (var i in catgoryIds.Added)
            {
                var categoryProduct = new CategoryProduct()
                {
                     CategoryId = i,
                      ProductId = product.Id
                };
                DataWriterContext.CategoryProducts.InsertOnSubmit(categoryProduct);
            }

            #endregion

            this.DataWriterContext.SubmitChanges();
        }

        public void Delete(IProduct product)
        {
            if (product != null)
            {
                var item = this.DataWriterContext.Products
               .Where(i => i.Id == product.Id)
               .FirstOrDefault();

                if (item != null)
                {
                    //this.DataContext.ProductImages
                    //   .DeleteAllOnSubmit(this.DataContext.ProductImages.Where(i => i.ProductId == product.Id));

                    //this.DataContext.ProductCustomFields
                    //    .DeleteAllOnSubmit(this.DataContext.ProductCustomFields.Where(i => i.ProductId == item.Id));

                    //var variations = this.DataContext.ProductVariations
                    //    .Where(i=>i.ProductId == item.Id);

                    //this.DataContext.ProductVariationItems.DeleteAllOnSubmit(variations.SelectMany(i=>i.ProductVariationItems));

                    //this.DataContext.ProductVariations
                    //    .DeleteAllOnSubmit(variations);

                    this.DataWriterContext.Products.DeleteOnSubmit(item);

                    this.DataWriterContext.SubmitChanges();
                }
            }
        }

        #endregion
    }
}
